package com.heimdallr.config;

/**
 * Created by Administrator on 2016/8/11.
 */
import com.heimdallr.rbac.permission.entity.GroupEntity;
import com.heimdallr.rbac.permission.entity.PermissionEntity;
import com.heimdallr.rbac.permission.entity.RoleEntity;
import com.heimdallr.rbac.permission.entity.UserEntity;
import com.heimdallr.rbac.permission.service.IPermissionService;
import com.heimdallr.rbac.user.service.UserService;
import com.heimdallr.util.AppUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.Session;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.util.*;

/**
 * Shiro配置
 *
 **/

@Configuration
@Order(Ordered.LOWEST_PRECEDENCE-1)
public class ShiroConfig {

    private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
    /**
     * shiro过滤器，配置登录拦截等路由，并配置拦截规则
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(IPermissionService permissionService,RedisSessionDao redisSessionDao) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(getDefaultWebSecurityManager(redisSessionDao));
        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的连接
        shiroFilterFactoryBean.setSuccessUrl("/main");
        // 若访问页面无权限则跳转的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/login");
        // 加载过滤规则

        loadFilterChainDefinitions(shiroFilterFactoryBean,permissionService);
        return shiroFilterFactoryBean;
    }

    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(RedisSessionDao redisSessionDao) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(getMyShiroRealm());
        //缓存
        defaultWebSecurityManager.setCacheManager(getEhCacheManager());
        defaultWebSecurityManager.setSessionManager(getDefaultWebSessionManager(redisSessionDao));

        return defaultWebSecurityManager;
    }

    @Bean(name = "sessionManager")
    public DefaultWebSessionManager getDefaultWebSessionManager(RedisSessionDao redisSessionDao) {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionDAO(redisSessionDao);
        return defaultWebSessionManager;
    }


    @Bean(name="cacheManager")
    public CacheManager getEhCacheManager() {

        return new MemoryConstrainedCacheManager();
    }

    @Bean(name = "MyRealm")
    public MyRealm getMyShiroRealm() {
        MyRealm realm = new MyRealm();
        realm.setCacheManager(getEhCacheManager());
        return realm;
    }


    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     *shiroFilter权限控制规则
     */
    private void loadFilterChainDefinitions(ShiroFilterFactoryBean shiroFilterFactoryBean,IPermissionService permissionService){
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //这里写点固定不变的配置
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/*.txt", "anon");
        filterChainDefinitionMap.put("/clearCache", "anon");
        filterChainDefinitionMap.put("/logon", "anon");
        filterChainDefinitionMap.put("/signOut", "anon");
        filterChainDefinitionMap.put("/captcha", "anon");
        //静态资源
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/dist/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/plugins/**", "anon");

        //动态链接
        List<PermissionEntity> allPermissionList = permissionService.getAllPermissionEntity();
        for(PermissionEntity permissionEntity:allPermissionList){
            filterChainDefinitionMap.put(permissionEntity.getUrl(),"perms["+permissionEntity.getMapping()+"]");
        }

        //这个要放在最后，表示除了这个以外的都拦截不通过
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }

    /**
     * 重新加载数据库权限
     *
     * @author panxl
     * @createDate 2014-7-28 下午05:28:04
     */
    public synchronized void reCreateFilterChains(IPermissionService permissionService, RedisSessionDao redisSessionDao, UserService userService) {
        AbstractShiroFilter shiroFilter ;
        PathMatchingFilterChainResolver filterChainResolver ;
        DefaultFilterChainManager manager ;
        ShiroFilterFactoryBean shiroFilterFactoryBean  = getShiroFilterFactoryBean(permissionService,redisSessionDao);
        DefaultWebSecurityManager securityManager ;

        try {
            shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean
                    .getObject();
            filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
                    .getFilterChainResolver();
            manager = (DefaultFilterChainManager) filterChainResolver
                    .getFilterChainManager();
            securityManager = (DefaultWebSecurityManager) shiroFilterFactoryBean.getSecurityManager();

        } catch (Exception e) {
            throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
        }

        // 清空老的权限控制
        manager.getFilterChains().clear();

        shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
        loadFilterChainDefinitions(shiroFilterFactoryBean,permissionService);

        // 重新构建生成
        Map<String, String> chains = shiroFilterFactoryBean
                .getFilterChainDefinitionMap();
        for (Map.Entry<String, String> entry : chains.entrySet()) {
            String url = entry.getKey();
            String chainDefinition = entry.getValue().trim().replace(" ", "");
            manager.createChain(url, chainDefinition);
        }

        Collection<Realm> userRealm = securityManager.getRealms();
        Subject subject = SecurityUtils.getSubject();

        for (Realm realm : userRealm) {

            MyRealm myRealm = (MyRealm) realm;

            Cache<Object, AuthorizationInfo> cache = myRealm.getAuthorizationCache();

            Session session = subject.getSession();
            if (session == null) {
                continue;
            }
            String currentUser = (String) session.getAttribute("currentUser");
            if (AppUtils.isNull(currentUser)) {
                continue;
            }
            UserEntity userEntity = userService.getUserEntityByUserName(currentUser);
            if(userEntity==null){continue;}

            SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();

            GroupEntity groupEntity = userEntity.getGroupEntity();
            List<RoleEntity> roleEntityList = groupEntity.getRoleEntityList();
            for (RoleEntity roleEntity : roleEntityList) {
                List<PermissionEntity> permissionEntityList = roleEntity.getPermissionEntityList();
                permissionEntityList.stream().forEach(permissionEntity ->
                        simpleAuthorInfo.addStringPermission(permissionEntity.getMapping()));
                simpleAuthorInfo.addRole(roleEntity.getRoleName());
            }

            cache.keys().stream().forEach(key->{
                if(key.toString().equals(currentUser)){
                    cache.put(key,simpleAuthorInfo);
                }
            });
            
        }//end foreach



    }


}
